package com.sky.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Word文档处理工具类
 */
@Slf4j
public class WordDocumentUtil {

    /**
     * 根据模板生成Word文档
     * @param templatePath 模板文件路径（相对于resources目录）
     * @param data 要填充的数据对象
     * @param outputFileName 输出文件名（不包含路径）
     * @return 生成的临时文件路径
     */
    public static String generateDocument(String templatePath, Object data, String outputFileName) {
        try {
            // 读取模板文件
            ClassPathResource resource = new ClassPathResource(templatePath);
            InputStream templateInputStream = resource.getInputStream();
            XWPFDocument document = new XWPFDocument(templateInputStream);
            // 填充数据
            fillDocumentData(document, data);
            // 生成临时文件
            String tempFilePath = createTempFile(document, outputFileName);
            document.close();
            templateInputStream.close();
            log.info("Word文档生成成功: {}", tempFilePath);
            return tempFilePath;
        } catch (Exception e) {
            log.error("生成Word文档失败", e);
            throw new RuntimeException("生成Word文档失败: " + e.getMessage());
        }
    }

    /**
     * 填充文档数据
     */
    private static void fillDocumentData(XWPFDocument document, Object data) throws Exception {
        // 获取数据对象的所有字段
        Map<String, Object> fieldMap = objectToMap(data);
        log.info("填充数据: {}", fieldMap);
        // 替换段落中的占位符
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            replaceInParagraph(paragraph, fieldMap);
        }
        // 替换表格中的占位符
        for (XWPFTable table : document.getTables()) {
            replaceInTable(table, fieldMap);
        }
        // 替换页眉页脚中的占位符
        for (XWPFHeader header : document.getHeaderList()) {
            for (XWPFParagraph paragraph : header.getParagraphs()) {
                replaceInParagraph(paragraph, fieldMap);
            }
        }
        for (XWPFFooter footer : document.getFooterList()) {
            for (XWPFParagraph paragraph : footer.getParagraphs()) {
                replaceInParagraph(paragraph, fieldMap);
            }
        }
    }

    /**
     * 替换段落中的占位符 - 强化处理跨Run的占位符
     */
    private static void replaceInParagraph(XWPFParagraph paragraph, Map<String, Object> data) {
        // 先尝试合并段落文本，处理跨Run的占位符
        String fullText = paragraph.getText();
        if (fullText != null && fullText.contains("${")) {
            // 移除所有换行符和空格，重新组装占位符
            String cleanText = fullText.replaceAll("\\s+", "").replaceAll("\\n", "").replaceAll("\\r", "");
            // 处理跨Run的占位符替换
            String newText = fullText;
            boolean hasReplacement = false;
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                String placeholder = "${" + entry.getKey() + "}";
                String cleanPlaceholder = placeholder.replaceAll("\\s+", "").replaceAll("\\n", "").replaceAll("\\r", "");
                // 检查清理后的文本是否包含占位符
                if (cleanText.contains(cleanPlaceholder)) {
                    String value = entry.getValue() != null ? entry.getValue().toString() : "";
                    // 使用正则表达式替换，处理占位符中可能存在的空白字符
                    String regex = "\\$\\{\\s*" + entry.getKey().replace(".", "\\.") + "\\s*\\}";
                    newText = newText.replaceAll(regex, value);
                    hasReplacement = true;
                    log.info("替换段落占位符: {} -> {}", placeholder, value);
                }
                // 也检查原始文本
                if (newText.contains(placeholder)) {
                    String value = entry.getValue() != null ? entry.getValue().toString() : "";
                    newText = newText.replace(placeholder, value);
                    hasReplacement = true;
                    log.info("替换段落占位符: {} -> {}", placeholder, value);
                }
            }

            // 如果文本发生了变化，重新设置段落内容
            if (hasReplacement) {
                // 清除所有Run
                for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
                    paragraph.removeRun(i);
                }
                // 添加新的Run
                XWPFRun newRun = paragraph.createRun();
                newRun.setText(newText);
                return;
            }
        }

        // 如果没有跨Run的占位符，使用原来的逐个Run处理方式
        for (XWPFRun run : paragraph.getRuns()) {
            String text = run.getText(0);
            if (text != null) {
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    String placeholder = "${" + entry.getKey() + "}";
                    if (text.contains(placeholder)) {
                        String value = entry.getValue() != null ? entry.getValue().toString() : "";
                        text = text.replace(placeholder, value);
                        run.setText(text, 0);
                    }
                }
            }
        }
    }

    /**
     * 替换表格中的占位符
     */
    private static void replaceInTable(XWPFTable table, Map<String, Object> data) {
        // 调试：打印表格内容
        debugTableContent(table);
        for (int i = 0; i < table.getRows().size(); i++) {
            XWPFTableRow row = table.getRow(i);
            // 检查是否是动态数据行（包含动态占位符）
            if (isDynamicRow(row)) {
                log.info("发现动态数据行，行索引: {}", i);
                handleDynamicTableRows(table, row, i, data);
                break; // 处理完动态行后跳出循环
            } else {
                // 处理普通单元格
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replaceInParagraph(paragraph, data);
                    }
                }
            }
        }
    }
    /**
     * 检查是否是动态数据行 - 改进跨段落占位符检测
     */
    private static boolean isDynamicRow(XWPFTableRow row) {
        for (XWPFTableCell cell : row.getTableCells()) {
            // 合并单元格内所有段落的文本
            StringBuilder cellText = new StringBuilder();
            for (XWPFParagraph paragraph : cell.getParagraphs()) {
                String fullText = paragraph.getText();
                if (fullText != null) {
                    cellText.append(fullText);
                }
            }

            String fullCellText = cellText.toString();
            if (fullCellText != null) {
                // 移除所有换行符和空格进行检查
                String cleanText = fullCellText.replaceAll("\\s+", "")
                                              .replaceAll("\\r?\\n", "");

                // 检查是否包含teacher占位符模式
                boolean hasTeacherPlaceholder = cleanText.contains("${teacher") && cleanText.contains("}");

                // 检查是否包含teacher字段关键字
                boolean hasTeacherField = fullCellText.contains("teacher") &&
                    (fullCellText.contains("name") ||
                     fullCellText.contains("education") ||
                     fullCellText.contains("title") ||
                     fullCellText.contains("department") ||
                     fullCellText.contains("remarks"));

                if (hasTeacherPlaceholder || hasTeacherField) {
                    log.info("检测到动态数据行，单元格完整文本: [{}]", fullCellText);
                    log.info("清理后文本: [{}]", cleanText);
                    log.info("检测条件 - hasTeacherPlaceholder: {}, hasTeacherField: {}",
                            hasTeacherPlaceholder, hasTeacherField);
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 处理动态表格行 - 支持指导教师垂直合并单元格结构
     */
    private static void handleDynamicTableRows(XWPFTable table, XWPFTableRow templateRow, int templateRowIndex, Map<String, Object> data) {
        // 只查找teacher字段
        Object listData = data.get("teacher");
        if (!(listData instanceof List)) {
            log.warn("未找到teacher列表数据，跳过动态行处理");
            return;
        }

        List<?> dataList = (List<?>) listData;
        log.info("处理动态表格行，teacher列表数据大小: {}", dataList.size());

        // 先保存模板行的结构信息（包含占位符）
        TemplateRowInfo templateInfo = saveTemplateRowInfo(templateRow);
        log.info("保存的模板信息: 单元格数量={}", templateInfo.cellCount);

        // 确保至少有3行数据（即使数据为空）
        int dataRowsToCreate = Math.max(3, dataList.size());
        log.info("将创建数据行数: {}", dataRowsToCreate);

        // 删除原模板行
        table.removeRow(templateRowIndex);
        log.info("已删除模板行，索引: {}", templateRowIndex);

        // 创建数据行并填充
        for (int i = 0; i < dataRowsToCreate; i++) {
            XWPFTableRow dataRow = table.insertNewTableRow(templateRowIndex + i);

            // 复制模板行的结构
            copyTemplateRowStructure(dataRow, templateInfo);

            // 填充数据
            if (i < dataList.size()) {
                Object item = dataList.get(i);
                fillTeacherRowWithTemplateData(dataRow, item, templateInfo);
                log.info("填充第{}行数据", i);
            } else {
                fillEmptyTeacherRowWithTemplate(dataRow, templateInfo);
                log.info("第{}行为空行", i);
            }
        }

        // 调整指导教师列的合并行数
        adjustTeacherMergedRows(table, templateRowIndex, dataRowsToCreate);

        log.info("动态表格行处理完成，总共创建了{}行数据", dataRowsToCreate);
    }





    /**
     * 将对象转换为Map
     */
    private static Map<String, Object> objectToMap(Object obj) throws Exception {
        Map<String, Object> map = new java.util.HashMap<>();
        if (obj == null) {
            return map;
        }

        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(obj);

            // 对于null值，转换为空字符串
            if (value == null) {
                map.put(field.getName(), "");
            } else {
                map.put(field.getName(), value);
            }
        }

        log.debug("对象转Map结果: {}", map);
        return map;
    }

    /**
     * 创建临时文件到指定目录
     */
    private static String createTempFile(XWPFDocument document, String fileName) throws Exception {
        // 生成唯一的文件名
        String uniqueFileName = UUID.randomUUID().toString() + "_" + fileName;
        // 使用resources/File/temp目录作为临时文件存储位置
        String tempDir = getResourcesTempDir();
        String tempFilePath = tempDir + File.separator + uniqueFileName;

        // 确保目录存在
        File directory = new File(tempDir);
        if (!directory.exists()) {
            directory.mkdirs();
        }

        // 写入文件
        try (FileOutputStream out = new FileOutputStream(tempFilePath)) {
            document.write(out);
        }

        return tempFilePath;
    }

    /**
     * 获取resources/File/temp目录路径
     */
    private static String getResourcesTempDir() {
        try {
            // 获取resources目录路径
            ClassPathResource resource = new ClassPathResource("");
            String resourcesPath = resource.getFile().getPath();
            return resourcesPath + File.separator + "File" + File.separator + "temp";
        } catch (Exception e) {
            // 如果获取resources路径失败，使用项目根目录下的temp
            return System.getProperty("user.dir") + File.separator + "temp";
        }
    }

    /**
     * 生成Word文档并返回相对路径（用于存储到数据库）
     * @param templatePath 模板文件路径
     * @param data 数据对象
     * @param outputFileName 输出文件名
     * @return 相对于resources的文件路径
     */
    public static String generateDocumentForStorage(String templatePath, Object data, String outputFileName) {
        try {
            // 读取模板文件
            ClassPathResource resource = new ClassPathResource(templatePath);
            InputStream templateInputStream = resource.getInputStream();
            XWPFDocument document = new XWPFDocument(templateInputStream);
            // 填充数据
            fillDocumentData(document, data);
            // 生成临时文件
            String tempFilePath = createTempFile(document, outputFileName);
            document.close();
            templateInputStream.close();
            // 返回相对路径（用于存储到数据库）
            String relativePath = "File/temp/" + new File(tempFilePath).getName();
            log.info("Word文档生成成功，相对路径: {}", relativePath);
            return relativePath;
        } catch (Exception e) {
            log.error("生成Word文档失败", e);
            throw new RuntimeException("生成Word文档失败: " + e.getMessage());
        }
    }

    /**
     * 获取临时目录下的文件输入流
     */
    public static InputStream getTempFileInputStream(String tempFilePath) throws FileNotFoundException {
        return new FileInputStream(tempFilePath);
    }

    /**
     * 删除临时文件
     */
    public static boolean deleteTempFile(String tempFilePath) {
        try {
            File file = new File(tempFilePath);
            return file.delete();
        } catch (Exception e) {
            log.error("删除临时文件失败: {}", tempFilePath, e);
            return false;
        }
    }

    /**
     * 修复跨段落分割的占位符
     */
    private static String fixBrokenPlaceholder(String text) {
        log.info("修复前文本: [{}]", text);

        // 移除所有换行符和多余空格，这些是Word自动换行造成的
        String cleanedText = text.replaceAll("\\s+", "")
                                .replaceAll("\\r?\\n", "")
                                .trim();
        log.info("清理换行和空格后文本: [{}]", cleanedText);

        // 直接根据清理后的文本重建标准占位符
        String result = rebuildStandardPlaceholder(cleanedText);

        log.info("修复后文本: [{}]", result);
        return result;
    }

    /**
     * 重建标准占位符格式
     */
    private static String rebuildStandardPlaceholder(String cleanText) {
        // 检查是否包含teacher相关的完整模式
        if (cleanText.contains("${teacher") && cleanText.contains("}")) {

            // 匹配各个字段
            if (cleanText.contains("name")) {
                log.info("重建name字段占位符");
                return "${teacher.name}";
            }
            else if (cleanText.contains("education")) {
                log.info("重建education字段占位符");
                return "${teacher.education}";
            }
            else if (cleanText.contains("title")) {
                log.info("重建title字段占位符");
                return "${teacher.title}";
            }
            else if (cleanText.contains("department")) {
                log.info("重建department字段占位符");
                return "${teacher.department}";
            }
            else if (cleanText.contains("remarks")) {
                log.info("重建remarks字段占位符");
                return "${teacher.remarks}";
            }
        }

        // 如果不是标准格式，返回原文本
        return cleanText;
    }
    /**
     * 调试方法：打印表格中的所有文本内容
     */
    private static void debugTableContent(XWPFTable table) {
        log.info("=== 开始调试表格内容 ===");
        for (int i = 0; i < table.getRows().size(); i++) {
            XWPFTableRow row = table.getRow(i);
            log.info("第{}行:", i);
            for (int j = 0; j < row.getTableCells().size(); j++) {
                XWPFTableCell cell = row.getCell(j);
                log.info("  第{}列:", j);
                for (int k = 0; k < cell.getParagraphs().size(); k++) {
                    XWPFParagraph paragraph = cell.getParagraphs().get(k);
                    String fullText = paragraph.getText();
                    log.info("    段落{}全文: [{}]", k, fullText);

                    for (int l = 0; l < paragraph.getRuns().size(); l++) {
                        XWPFRun run = paragraph.getRuns().get(l);
                        String runText = run.getText(0);
                        log.info("      Run{}: [{}]", l, runText);
                    }
                }
            }
        }
        log.info("=== 表格内容调试结束 ===");
    }



    /**
     * 模板行信息类
     */
    private static class TemplateRowInfo {
        String[] cellTexts;
        int cellCount;
        TemplateRowInfo(String[] cellTexts, int cellCount) {
            this.cellTexts = cellTexts;
            this.cellCount = cellCount;
        }
    }

    /**
     * 保存模板行信息
     */
    private static TemplateRowInfo saveTemplateRowInfo(XWPFTableRow templateRow) {
        try {
            int cellCount = templateRow.getTableCells().size();
            String[] cellTexts = new String[cellCount];

            for (int i = 0; i < cellCount; i++) {
                XWPFTableCell cell = templateRow.getCell(i);
                cellTexts[i] = cell.getText();
            }
            return new TemplateRowInfo(cellTexts, cellCount);
        } catch (Exception e) {
            log.error("保存模板行信息失败", e);
            return new TemplateRowInfo(new String[0], 0);
        }
    }



    /**
     * 复制模板行结构（保持原有格式和占位符）
     */
    private static void copyTemplateRowStructure(XWPFTableRow newRow, TemplateRowInfo templateInfo) {
        try {
            // 确保新行有足够的单元格
            while (newRow.getTableCells().size() < templateInfo.cellCount) {
                newRow.createCell();
            }
            // 复制模板内容（包含占位符）到新行
            for (int i = 0; i < templateInfo.cellCount && i < newRow.getTableCells().size(); i++) {
                XWPFTableCell cell = newRow.getCell(i);
                String templateText = i < templateInfo.cellTexts.length ? templateInfo.cellTexts[i] : "";
                setCellText(cell, templateText);
            }
        } catch (Exception e) {
            log.error("复制模板行结构失败", e);
        }
    }

    /**
     * 使用模板数据填充教师行
     */
    private static void fillTeacherRowWithTemplateData(XWPFTableRow row, Object itemData, TemplateRowInfo templateInfo) {
        try {
            Map<String, Object> itemMap = objectToMap(itemData);
            log.info("填充教师行数据: {}", itemMap);

            // 遍历每个单元格，替换占位符
            for (int i = 0; i < row.getTableCells().size(); i++) {
                XWPFTableCell cell = row.getCell(i);
                String cellText = cell.getText();

                // 修复可能被分割的占位符
                cellText = fixBrokenPlaceholder(cellText);

                // 替换teacher占位符
                String newText = cellText;
                for (Map.Entry<String, Object> entry : itemMap.entrySet()) {
                    String placeholder = "${teacher." + entry.getKey() + "}";
                    if (newText.contains(placeholder)) {
                        String value = entry.getValue() != null ? entry.getValue().toString() : "";
                        newText = newText.replace(placeholder, value);
                        log.info("替换占位符: {} -> {}", placeholder, value);
                    }
                }

                // 设置新文本
                setCellText(cell, newText);
            }
        } catch (Exception e) {
            log.error("填充教师行数据失败", e);
        }
    }

    /**
     * 使用模板填充空教师行
     */
    private static void fillEmptyTeacherRowWithTemplate(XWPFTableRow row, TemplateRowInfo templateInfo) {
        try {
            // 遍历每个单元格，将teacher占位符替换为空字符串
            for (int i = 0; i < row.getTableCells().size(); i++) {
                XWPFTableCell cell = row.getCell(i);
                String cellText = cell.getText();

                // 修复可能被分割的占位符
                cellText = fixBrokenPlaceholder(cellText);

                // 将所有teacher占位符替换为空字符串
                String newText = cellText;
                String[] fields = {"name", "education", "title", "department", "remarks"};
                for (String field : fields) {
                    String placeholder = "${teacher." + field + "}";
                    newText = newText.replace(placeholder, "");
                }

                // 设置新文本
                setCellText(cell, newText);
            }
        } catch (Exception e) {
            log.error("填充空教师行失败", e);
        }
    }

    /**
     * 调整指导教师列的合并行数（实现垂直合并效果）
     */
    private static void adjustTeacherMergedRows(XWPFTable table, int startRowIndex, int dataRowCount) {
        try {
            log.info("调整指导教师列合并行数，起始行: {}, 数据行数: {}", startRowIndex, dataRowCount);

            // 实现垂直合并的视觉效果：保持第一行内容，清空其他行
            for (int i = 0; i < dataRowCount; i++) {
                XWPFTableRow row = table.getRow(startRowIndex + i);
                if (row != null && row.getTableCells().size() > 0) {
                    XWPFTableCell firstCell = row.getCell(0);

                    if (i == 0) {
                        // 第一行：保持原有的"指导教师"内容
                        log.info("保持第{}行第一列原有内容", i);
                    } else {
                        // 后续行：清空内容，模拟合并效果
                        setCellText(firstCell, "");
                        log.info("清空第{}行第一列内容", i);
                    }
                }
            }

            log.info("指导教师列合并效果完成");
        } catch (Exception e) {
            log.error("调整指导教师列合并行数失败", e);
        }
    }

    /**
     * 设置单元格文本（防止竖直排列）
     */
    private static void setCellText(XWPFTableCell cell, String text) {
        try {
            // 清除所有现有段落
            while (cell.getParagraphs().size() > 1) {
                cell.removeParagraph(cell.getParagraphs().size() - 1);
            }

            XWPFParagraph para;
            if (cell.getParagraphs().isEmpty()) {
                para = cell.addParagraph();
            } else {
                para = cell.getParagraphs().get(0);
            }

            // 清除现有Run
            while (para.getRuns().size() > 0) {
                para.removeRun(0);
            }

            // 设置新文本，确保在一行显示
            if (text != null && !text.trim().isEmpty()) {
                XWPFRun run = para.createRun();
                // 替换可能导致换行的字符
                String cleanText = text.replace("\n", " ").replace("\r", " ").trim();
                run.setText(cleanText);

                // 防止文本方向变为竖直
                para.setAlignment(org.apache.poi.xwpf.usermodel.ParagraphAlignment.LEFT);
            }

            log.debug("设置单元格文本: [{}]", text);
        } catch (Exception e) {
            log.error("设置单元格文本失败: {}", text, e);
        }
    }

}
